﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
namespace DeploymentMaxLib
{

    //public class XMLDocument :System.Xml.XmlDocument
    //{

    //    public FrXMLDocument(string pXML, bool pIngoreNamespaces)
    //    {

    //        if (pIngoreNamespaces)
    //        {
    //            pXML = StripXmlDeclarationAndNamespaces(pXML);
    //        }

    //        pXmlDocument.LoadXml(pXML);

    //    }

    //    public static string StripXmlDeclarationAndNamespaces(string pXML)
    //    {
    //        pXML = System.Text.RegularExpressions.Regex.Replace(pXML, @"(xmlns:?[^=]*=[""][^""]*[""])", "", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Multiline);
    //        pXML = System.Text.RegularExpressions.Regex.Replace(pXML, @"(xsi:?[^=]*=[""][^""]*[""])", "", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Multiline);
    //        pXML = System.Text.RegularExpressions.Regex.Replace(pXML, @"([a-zA-Z0-9]+:nil[^=]*=[""][^""]*[""])", "", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Multiline);
    //        pXML = System.Text.RegularExpressions.Regex.Replace(pXML, @"(\<\?.*\?\>)", "", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Multiline);
    //        pXML = System.Text.RegularExpressions.Regex.Replace(pXML, @"([a-zA-Z0-9]+:type[^=]*=[""][^""]*[""])", "", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Multiline);

    //        return pXML;
    //    }
    //}


    public static class SystemXmlDocumentExt
    {
        public static XmlElement GetBuildElement(this XmlElement pElement, string pXPath)
        {
            bool tRoot = false;
            string[] tElems = pXPath.Split('/');
            XmlElement tCurElem = pElement;// null;
            //XmlAttribute tAttr = null;
            foreach (string tElem in tElems)
            {
                if (tElem.Trim().Length > 0 && tRoot != true)
                {

                    if (tCurElem.SelectSingleNode(tElem) == null)
                    {
                        XmlElement tTElem = pElement.OwnerDocument.CreateElement(tElem);
                        tCurElem.AppendChild((XmlNode)tTElem);
                        tCurElem = tTElem;
                    }
                    else
                    {
                        tCurElem = (XmlElement)tCurElem.SelectSingleNode(tElem);
                    }

                }
                else
                {
                    tRoot = !tRoot;
                }
                //				}
            }

            return tCurElem;
        }

        public static void SetElementValueByXPath(this XmlElement pElement, string pXPath, string pValue, bool pCreateIfNotExist)
        {
            XmlNode tNode = pElement.SelectSingleNode(pXPath);
            if (tNode == null && pCreateIfNotExist)
            {
                tNode = pElement.GetBuildElement(pXPath);
            }
            tNode.InnerText = pValue;

        }

        public static void SetElementInnnextXmlByXPath(this XmlElement pElement, string pXPath, string pInnnextXml, bool pCreateIfNotExist)
        {
            XmlNode tNode = pElement.SelectSingleNode(pXPath);
            if (tNode == null && pCreateIfNotExist)
            {
                tNode = pElement.GetBuildElement(pXPath);
            }
            tNode.InnerXml = pInnnextXml;

        }

        public static void SetElementValueByXPath(this XmlElement pElement, string pXPath, DateTime pValue, bool pCreateIfNotExist)
        {
            XmlNode tNode = pElement.SelectSingleNode(pXPath);
            if (tNode == null && pCreateIfNotExist)
            {
                tNode = pElement.GetBuildElement(pXPath);
            }
            tNode.InnerText = pValue.ToString();

        }


        public static void RemoveNodes(this XmlElement pElem, string pXPath)
        {
            System.Xml.XmlNode tParentNode = null;

            if (pElem.SelectSingleNode(pXPath) != null)
            {
                tParentNode = pElem.SelectSingleNode(pXPath).ParentNode;

                System.Xml.XmlNodeList tNodeList = pElem.SelectNodes(pXPath);

                foreach (XmlNode tNode in tNodeList)
                {
                    tParentNode.RemoveChild(tNode);
                }
            }

        }

        public static string DataEval(this XmlElement pElem, string pXPath, string pEmptyDefalut)
        {
            if (pElem == null) return pEmptyDefalut;
            XmlNode tNode;

            try
            {

                tNode = pElem.SelectSingleNode(pXPath);
                if (tNode != null)
                {
                    if (tNode.NodeType == XmlNodeType.Attribute)
                    {
                        return tNode.Value;
                    }
                    else
                    {
                        return tNode.InnerText;
                    }
                }
                else
                {
                    return pEmptyDefalut;
                }
            }
            catch
            {
                return pEmptyDefalut;
            }
        }
        public static string DataEval(this XmlElement pElem, string pXPath)
        {
            return DataEval(pElem, pXPath, "");
        }


        public static bool DataEval(this XmlElement pElem, string pXPath, bool pEmptyDefalut)
        {
            string tVal = DataEval(pElem, pXPath, "");

            bool tOut = false;
            if (bool.TryParse(tVal, out tOut))
            {
                return tOut;
            }
            else
            {
                if (tVal.ToUpper() == "Y" || tVal.ToUpper() == "YES" || tVal.ToUpper() == "1" || tVal.ToUpper() == "T" || tVal.ToUpper() == "TRUE")
                    return true;
                else if (tVal.ToUpper() == "N" || tVal.ToUpper() == "NO" || tVal.ToUpper() == "0" || tVal.ToUpper() == "F" || tVal.ToUpper() == "FALSE")
                    return false;
                else
                    return pEmptyDefalut;
            }

        }

        public static float DataEval(this XmlElement pElem, string pXPath, float pEmptyDefalut)
        {
            string tVal = DataEval(pElem, pXPath, "");

            float tOut = 0;
            if (float.TryParse(tVal, out tOut))
            {
                return tOut;
            }
            else
            {
                return pEmptyDefalut;
            }

        }

        public static DateTime DataEval(this XmlElement pElem, string pXPath, DateTime pEmptyDefalut)
        {
            string tVal = DataEval(pElem, pXPath, "");

            DateTime tOut = DateTime.MinValue;
            if (DateTime.TryParse(tVal, out tOut))
            {
                return tOut;
            }
            else
            {
                return pEmptyDefalut;
            }
        }

        public static int DataEval(this XmlElement pElem, string pXPath, int pEmptyDefalut)
        {
            string tVal = DataEval(pElem, pXPath, "");

            int tOut = 0;
            if (int.TryParse(tVal, out tOut))
            {
                return tOut;
            }
            else
            {
                return pEmptyDefalut;
            }
        }

        public static string GetValues(this XmlElement pElem, string pListXPath, string pValueXPath, string pValueSeparator)
        {
            string tResult = "";

            foreach (System.Xml.XmlNode tNode in pElem.SelectNodes(pListXPath))
            {
                System.Xml.XmlElement tItem = (System.Xml.XmlElement)tNode;
                tResult = tResult + pValueSeparator + tItem.DataEval(pValueXPath);
            }
            if (tResult.Length > 0) tResult = tResult.Substring(pValueSeparator.Length);

            return tResult;

        }

        public static string GetValues(this XmlElement pElem, string pListXPath, string pValueXPath, string pValueSeparator, string pSubValueXPath, string pSubValueSeparator)
        {
            string tResult = "";

            foreach (System.Xml.XmlNode tNode in pElem.SelectNodes(pListXPath))
            {
                System.Xml.XmlElement tItem = (System.Xml.XmlElement)tNode;
                tResult = tResult + pValueSeparator + GetValues(tItem, pValueXPath, pSubValueXPath, pSubValueSeparator);
            }
            if (tResult.Length > 0) tResult = tResult.Substring(pValueSeparator.Length);

            return tResult;

        }
 

 


        public static void RemoveNodes(this System.Xml.XmlDocument pXmlDocument, string pXPath)
        {
            if (pXmlDocument.DocumentElement == null) return;
            pXmlDocument.DocumentElement.RemoveNodes(pXPath);
        }

        public static XmlAttribute GetBuildAttribute(this System.Xml.XmlDocument pXmlDocument, string pXPath)
        {
            string[] tElems = pXPath.Split('/');
            XmlElement tCurElem = pXmlDocument.DocumentElement;//null;
            XmlAttribute tAttr = null;
            foreach (string tElem in tElems)
            {
                if (tElem.Substring(0, 1) == "@")
                {
                    tAttr = pXmlDocument.CreateAttribute(tElem.Substring(1));
                    tCurElem.Attributes.Append(tAttr);
                }
                else
                {
                    if (tCurElem.SelectSingleNode(tElem) == null)
                    {
                        XmlElement tTElem = pXmlDocument.CreateElement(tElem);
                        tCurElem.AppendChild((XmlNode)tTElem);
                        tCurElem = tTElem;
                    }
                    else
                    {
                        tCurElem = (XmlElement)tCurElem.SelectSingleNode(tElem);
                    }
                }

            }

            return tAttr;
        }
        public static XmlElement GetBuildElement(this System.Xml.XmlDocument pXmlDocument, string pXPath)
        {
            if (pXmlDocument.DocumentElement == null)
            {
                if (pXPath.Substring(0, 1) != "/")
                {
                    pXmlDocument.AppendChild(pXmlDocument.CreateElement("root"));
                }
                else
                {
                    pXmlDocument.AppendChild(pXmlDocument.CreateElement(pXPath.Split('/')[1]));
                }
            }

            return pXmlDocument.DocumentElement.GetBuildElement(pXPath);
        }


   
        public static void SetAttributeByXPath(this System.Xml.XmlDocument pXmlDocument, string pXPath, string pValue, bool pCreateIfNotExist)
        {

            XmlNode tNode = pXmlDocument.DocumentElement.SelectSingleNode(pXPath);
            if (tNode == null && pCreateIfNotExist)
            {
                tNode = pXmlDocument.GetBuildAttribute(pXPath);
            }
            tNode.Value = pValue;
        }

        public static void SetElementValueByXPath(this System.Xml.XmlDocument pXmlDocument, string pXPath, string pValue, bool pCreateIfNotExist)
        {
            if (pXmlDocument.DocumentElement == null)
            {
                if (pCreateIfNotExist)
                {
                    if (pXPath.Substring(0, 1) != "/")
                    {
                        pXmlDocument.AppendChild(pXmlDocument.CreateElement("root"));
                    }
                    else
                    {
                        pXmlDocument.AppendChild(pXmlDocument.CreateElement(pXPath.Split('/')[1]));
                    }
                }
            }

            pXmlDocument.DocumentElement.SetElementValueByXPath(pXPath, pValue, pCreateIfNotExist);
        }

        public static void SetAttributeByXPath(this System.Xml.XmlDocument pXmlDocument, string pXPath, string pValue)
        {
            pXmlDocument.DocumentElement.SetElementValueByXPath(pXPath, pValue, false);
        }

        public static void SetElementValueByXPath(this System.Xml.XmlDocument pXmlDocument, string pXPath, string pValue)
        {
            pXmlDocument.SetElementValueByXPath(pXPath, pValue, false);
        }


        public static string DataEval(this System.Xml.XmlDocument pXmlDocument, string pXPath, string pEmptyDefalut)
        {
            return pXmlDocument.DocumentElement.DataEval(pXPath, pEmptyDefalut);
        }

        public static string DataEval(this System.Xml.XmlDocument pXmlDocument, string pXPath)
        {
            return pXmlDocument.DataEval(pXPath, "");
        }

        public static bool DataEval(this System.Xml.XmlDocument pXmlDocument, string pXPath, bool pEmptyDefalut)
        {
            string tVal = pXmlDocument.DataEval(pXPath, "");
            bool tOut = false;
            if (bool.TryParse(tVal, out tOut))
            {
                return tOut;
            }
            else
            {
                return pEmptyDefalut;
            }
        }

        public static float DataEval(this System.Xml.XmlDocument pXmlDocument, string pXPath, float pEmptyDefalut)
        {
            string tVal = pXmlDocument.DataEval(pXPath, "");
            float tOut = 0;
            if (float.TryParse(tVal, out tOut))
            {
                return tOut;
            }
            else
            {
                return pEmptyDefalut;
            }
        }

        public static DateTime DataEval(this System.Xml.XmlDocument pXmlDocument, string pXPath, DateTime pEmptyDefalut)
        {
            string tVal = pXmlDocument.DataEval(pXPath, "");

            DateTime tOut = DateTime.MinValue;
            if (DateTime.TryParse(tVal, out tOut))
            {
                return tOut;
            }
            else
            {
                return pEmptyDefalut;
            }
        }

        public static int DataEval(this System.Xml.XmlDocument pXmlDocument, string pXPath, int pEmptyDefalut)
        {
            string tVal = pXmlDocument.DataEval(pXPath, "");
            int tOut = 0;
            if (int.TryParse(tVal, out tOut))
            {
                return tOut;
            }
            else
            {
                return pEmptyDefalut;
            }
        }

        public static string GetValues(this System.Xml.XmlDocument pXmlDocument, string pListXPath, string pValueXPath, string pValueSeparator)
        {

            return pXmlDocument.DocumentElement.GetValues(pListXPath, pValueXPath, pValueSeparator);

        }

        public static string GetValues(this System.Xml.XmlDocument pXmlDocument, string pListXPath, string pValueXPath, string pValueSeparator, string pSubValueXPath, string pSubValueSeparator)
        {

            return pXmlDocument.DocumentElement.GetValues(pListXPath, pValueXPath, pValueSeparator, pSubValueXPath, pSubValueSeparator);

        }

        public static System.Xml.XmlNodeList SelectNodes(this System.Xml.XmlDocument pXmlDocument, string pXPath, string pSortPath)
        {
            System.Collections.SortedList tSortedList = new System.Collections.SortedList();
            System.Xml.XmlNodeList tNodeList = pXmlDocument.SelectNodes(pXPath);
            XmlNode tSortByNode;
            int ii = 9999;

            if (tNodeList.Count > 0)
            {
                System.Xml.XmlNode tSortedNode = null;
                System.Xml.XmlNode tParentNode = null;

                string tKey = "";

                tParentNode = pXmlDocument.SelectSingleNode(pXPath);

                tParentNode = tParentNode.ParentNode;
                string tKey1 = "";
                //string tKey2 = "";

                foreach (XmlNode tNode in tNodeList)
                {
                    ii++;
                    //Find key by SortPath
                    tSortByNode = tNode.SelectSingleNode(pSortPath);
                    if (tSortByNode != null)
                    {
                        if (tSortByNode.NodeType == System.Xml.XmlNodeType.Element)
                        {
                            tKey1 = tSortByNode.InnerText;
                        }
                        else if (tSortByNode.NodeType == System.Xml.XmlNodeType.Attribute)
                        {
                            tKey1 = tSortByNode.Value;
                        }
                    }

                    tKey = tKey1 + ii.ToString();
                    tSortedList.Add(tKey, tNode);
                    tParentNode.RemoveChild(tNode);
                }

                for (int i = 0; i < tSortedList.Count; i++)
                {
                    tSortedNode = (System.Xml.XmlNode)tSortedList.GetByIndex(i);
                    tParentNode.AppendChild(tSortedNode);
                }

                return tParentNode.SelectNodes(pXPath);
            }
            else
            {
                return tNodeList;
            }
        }

        public static System.Xml.XmlNodeList SelectNodes(this System.Xml.XmlDocument pXmlDocument, string pXPath, string pSortPath1, string pSortPath2)
        {
            System.Collections.SortedList tSortedList = new System.Collections.SortedList();
            System.Xml.XmlNodeList tNodeList = pXmlDocument.SelectNodes(pXPath);
            XmlNode tSortByNode;
            int ii = 9999;
            string tKey1 = "", tKey2 = "";

            if (tNodeList.Count > 0)
            {
                System.Xml.XmlNode tSortedNode = null;
                System.Xml.XmlNode tParentNode = null;

                string tKey = "";

                tParentNode = pXmlDocument.SelectSingleNode(pXPath);

                tParentNode = tParentNode.ParentNode;

                foreach (XmlNode tNode in tNodeList)
                {
                    ii++;
                    tSortByNode = tNode.SelectSingleNode(pSortPath1);
                    if (tSortByNode != null)
                    {
                        if (tSortByNode.NodeType == System.Xml.XmlNodeType.Element)
                        {
                            tKey1 = tSortByNode.InnerText;
                        }
                        else if (tSortByNode.NodeType == System.Xml.XmlNodeType.Attribute)
                        {
                            tKey1 = tSortByNode.Value;
                        }


                        if (tSortByNode.NodeType == System.Xml.XmlNodeType.Element)
                        {
                            tKey2 = tSortByNode.InnerText;
                        }
                        else if (tSortByNode.NodeType == System.Xml.XmlNodeType.Attribute)
                        {
                            tKey2 = tSortByNode.Value;
                        }
                    }

                    //Find key by SortPath
                    tKey = tKey1 + tKey2 + ii.ToString();
                    tSortedList.Add(tKey, tNode);
                    tParentNode.RemoveChild(tNode);
                }

                for (int i = 0; i < tSortedList.Count; i++)
                {
                    tSortedNode = (System.Xml.XmlNode)tSortedList.GetByIndex(i);
                    tParentNode.AppendChild(tSortedNode);
                }

                return tParentNode.SelectNodes(pXPath);
            }
            else
            {
                return tNodeList;
            }
        }


        /// <summary>
        /// This procedure removes all repeating elements base on XPath parameter.
        /// </summary>
        /// <param name="pXPath"></param>
        /// <returns>Returns number of elements removed.</returns>
        public static int RemoveRepeatingElements(this System.Xml.XmlDocument pXmlDocument, string pXPath)
        {
            int tRemovedCount = 0;
            /// remove repeating elements.
            XmlElement tElem = (XmlElement)pXmlDocument.DocumentElement.SelectSingleNode(pXPath);
            while (tElem != null)
            {
                pXmlDocument.DocumentElement.RemoveChild(tElem);
                tElem = (XmlElement)pXmlDocument.DocumentElement.SelectSingleNode(pXPath);
                tRemovedCount++;
            }
            return tRemovedCount;
        }

        public static void RenameDocuemntElement(this System.Xml.XmlDocument pXmlDocument, string pNewName)
        {
            pXmlDocument.RenameNode(pXmlDocument.DocumentElement, pXmlDocument.DocumentElement.NamespaceURI, pNewName);
        }

        public static void RenameElement(this System.Xml.XmlDocument pXmlDocument, XmlElement pElement, string pNewName)
        {
            pXmlDocument.RenameNode(pElement, pElement.NamespaceURI, pNewName);
        }

        public static XmlNode RenameNode(this System.Xml.XmlDocument pXmlDocument, XmlNode node, string namespaceURI, string qualifiedName)
        {
            if (node.NodeType == XmlNodeType.Element)
            {
                XmlElement oldElement = (XmlElement)node;
                XmlElement newElement = pXmlDocument.CreateElement(qualifiedName, namespaceURI);
                while (oldElement.HasAttributes)
                {

                    newElement.SetAttributeNode(oldElement.RemoveAttributeNode(oldElement.Attributes[0]));
                }
                while (oldElement.HasChildNodes)
                {
                    newElement.AppendChild(oldElement.FirstChild);
                }
                if (oldElement.ParentNode != null)
                {
                    oldElement.ParentNode.ReplaceChild(newElement, oldElement);
                }
                return newElement;
            }
            else
            {
                return null;
            }
        }
    }

}
 